const path = require('path')
const fs = require('fs')
const LRU = require('lru-cache')
const { createBundleRenderer } = require('vue-server-renderer')
const Router = require('@koa/router')

const microCache = new LRU({
  max: 100,
  maxAge: 1000 * 60 * 15 // 超时时间（ms）
})

/**
 * 解析地址
 * @param {String} dir
 */
function resolve (dir) {
  return path.resolve(process.cwd(), dir)
}

/**
 * 创建SSR渲染器
 * @param {*} bundle
 * @param {*} options
 */
function createRenderer(bundle, options) {
  return createBundleRenderer(bundle, Object.assign(options, {
    // 组件缓存
    // cache: new LRU({
    //   max: 1000, // 最大的缓存个数
    //   maxAge: 1000 * 60 * 15 // 超时时间（ms）
    // }),
    runInNewContext: false
  }))
}

/**
 * 渲染数据
 * @param {*} context
 * @param {*} renderer
 */
function renderData (context, renderer) {
  return new Promise((resolve, reject) => {
    renderer.renderToString(context, (err, html) => {
      if (err) {
        reject(err)
      }

      resolve(html)
    })
  })
}

/**
 * 异常处理
 * @param {*} err
 * @param {*} res
 */
function errorHandler (err, ctx) {
  if (err.code === 404) {
    ctx.status = 404
    ctx.body = '404 | Not Found'
  } else if (err.code === 401) {
    ctx.status = 404
    ctx.body = '401 | Forbidden'
  } else {
    ctx.code = 500
    ctx.body = '500 | Internal Server Error'
  }
}

const template = fs.readFileSync(resolve('server/public/index.template.html'), 'utf-8')

const bundle = require(resolve('dist/vue-ssr-server-bundle.json'))
const clientManifest = require(resolve('dist/vue-ssr-client-manifest.json'))

const renderer = createRenderer(bundle, {
  template,
  clientManifest
})

const router = new Router()
router.get('/', async (ctx) => {
  ctx.type = 'text/html; charset=utf-8'

  if (!renderer) {
    ctx.status = 500
    ctx.body = 'SSR渲染服务异常!'
    return
  }

  ctx.status = 200
  ctx.body = 'SSR渲染服务正常!'
})

router.get('/generateForm', async (ctx) => {
  ctx.type = 'text/html; charset=utf-8'

  if (!renderer) {
    ctx.status = 500
    ctx.body = 'SSR渲染服务异常!'
    return
  }

  const query = ctx.query
  const cacheKey = query.id

  const hit = microCache.get(cacheKey)
  if (hit) {
    ctx.log.info(`命中缓存 ${cacheKey}, 返回缓存内容`)
    ctx.status = 200
    ctx.body = hit
    return
  }

  try {
    const context = { query, xAuthId: ctx.xAuthId, xAToken: ctx.xAToken }
    const html = await renderData(context, renderer)
    cacheKey && microCache.set(cacheKey, html)

    ctx.status = 200
    ctx.body = html
  } catch (e) {
    ctx.log.error(e)
    // if (e.code === -201 || e.code === -110) {
    //   next()
    // }
    errorHandler(e, ctx)
  }
})

module.exports = router